/*
 *
 *  V4L2 video capture example
 */

#ifndef _GmslCameraHandler_H
#define _GmslCameraHandler_H


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <getopt.h> /* getopt_long() */

#include <fcntl.h> /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>

#include "opencv2/core/cuda.hpp"
#include "opencv2/cudawarping.hpp"

#include <asm/types.h> /* for videodev2.h */

#include <linux/videodev2.h>

#include <cuda_runtime.h>
#include "yuyv2rgb.cuh"

#define CLEAR(x) memset(&(x), 0, sizeof(x))
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define PIXL_WIDTH		1920 
#define PIXL_WIDTH_N		2800 
#define PIXL_HEIGHT		1536


namespace v4l_cuda
{
    static void errno_exit(const char *s)
    {
        fprintf(stderr, "%s error %d, %s\n",
                s, errno, strerror(errno));

        exit(EXIT_FAILURE);
    }

    static int xioctl(int fd,
               int request,
               void *arg)
    {
        int r;

        do
            r = ioctl(fd, request, arg);
        while (-1 == r && EINTR == errno);

        return r;
    }

    typedef enum
    {
        IO_METHOD_READ,
        IO_METHOD_MMAP,
        IO_METHOD_USERPTR,
    } io_method;

    struct buffer
    {
        void *start;
        size_t length;
    };

    class GmslCameraHandler
    {

    private:
        std::string dev_name;
        io_method io = IO_METHOD_USERPTR;
        int fd = -1;
        struct buffer *buffers = NULL;
        unsigned int n_buffers = 0;
        unsigned int width = PIXL_WIDTH;
        unsigned int height = PIXL_HEIGHT;
        bool cuda_zero_copy = true;
        unsigned int pixel_format = V4L2_PIX_FMT_UYVY;
        unsigned int field = V4L2_FIELD_INTERLACED;
        void init_device();
        void uninit_device();
        void open_device();
        void init_cuda();
        void close_device();
        void start_capturing();
        void init_userp(unsigned int buffer_size);

    public:
        GmslCameraHandler(std::string device_name);
	    ~GmslCameraHandler(){};
        void start_camera();
        void close_camera();
        void stop_capturing();
        int read_frame();
        void process_image(void *p);
        unsigned char *out_buffer = NULL;
        unsigned char *out_yuv_buffer = NULL;
    };
}

#endif